package farmers.stream;

import com.alibaba.fastjson.JSON;
import org.junit.Test;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;

public class A001_list工具类 {

//        JDK1.8新特性 list使用stream排序(多字段)
//        1.stream()方法：将集合装为流
//        2.collect()方法：将流转为集合
//        3.filter()方法：将转为流的集合过滤出满足要求的流
//        4.map()方法：将每个元素映射成新元素
//        5.limit(n)：获取n个元素
//        6.skip(n)：跳过n元素
//        7.skip和limit组合实现分页（对数据库的压力没有减轻，只是看着分页了）
//        8.distinct：去除重复元素

    /**
     * 初始化list的 五种方法
     */
    @Test
    public void initList() {

        List<String> languages = new ArrayList<>();
        languages.add("Java");
        languages.add("PHP");
        languages.add("Python");
        System.out.println(languages);

        // 初始化 不可变 list， 往不可变list中添加数据会报错
        // 存在两个包：a、java.util.ArrayList包；
        //           b、java.util.Arrays.ArrayList包（重点）
        List<Integer> list1 = Arrays.asList(1, 2);
        System.out.println(list1);
//        list1.add(3);
        List<String> list2 = Arrays.asList("aa", "bb");
        System.out.println(list2);
//        list2.add("cc");

        // 初始化 可变 list
        List<Integer> list3 = new ArrayList<>(Arrays.asList(1, 2));
        list3.add(3);
        System.out.println(list3);
    }


    @Test
    public void lsit转其他集合() {
        // 字符串 转 List
        List<String> list = Arrays.asList("One", "Two", "Three", "Four", "Five", "Six", "Six");
        System.out.println("list = " + list);   // list = [One, Two, Three, Four, Five, Six, Six]

        List<String> newList = list.stream().collect(Collectors.toList());
        System.out.println("newList = " + newList);    // newList = [One, Two, Three, Four, Five, Six, Six]

        LinkedList<String> linkedList = list.stream().collect(Collectors.toCollection(LinkedList::new));
        System.out.println("linkedList = " + linkedList);   // linkedList = [One, Two, Three, Four, Five, Six, Six]

        ArrayList<String> arrayList = list.stream().collect(Collectors.toCollection(ArrayList::new));
        System.out.println("arrayList = " + arrayList);   // linkedList = [One, Two, Three, Four, Five, Six, Six]

        CopyOnWriteArrayList<String> copyOnWriteArrayList = list.stream().collect(Collectors.toCollection(CopyOnWriteArrayList::new));
        System.out.println("copyOnWriteArrayList = " + copyOnWriteArrayList);   // copyOnWriteArrayList = [One, Two, Three, Four, Five, Six, Six]

        Set<String> set = list.stream().collect(Collectors.toSet());
        System.out.println("set = " + set);     // set = [Five, Six, One, Four, Two, Three]


        ArrayList<House> houseList = new ArrayList<>();
        houseList.add(new House(1, 1, "aa", "北京海淀"));
        houseList.add(new House(2, 2, "bb", "湖北武汉"));
        houseList.add(new House(3, 3, "cc", "浙江杭州"));
        //在实际项目中我们经常会用到 List 转 Map 操作 ->过去是for循环的操作，现在可以学习如下的方法Collectors.toMap
        /**
         * 我们收集一下集合中每个对象的两个单独的属性
         */
        Map<String, String> mapHouse = houseList.stream().collect(Collectors.toMap(House::getHousename, House::getAddress));
        System.out.println(mapHouse);   //{aa=湖北武汉, bb=浙江杭州, cc=北京海淀}

        /**
         * 前后的属性的数据类型要对应  一般时间业务中收集带有唯一表示的业务数据
         */
        Map<Integer, String> map = houseList.stream().collect(Collectors.toMap(House::getOwnerid, House::getHousename));
        System.out.println(map);     //{1=aa, 2=bb, 3=cc}

        /**
         * 收集一下属性和对象本身
         */
        Map<Integer, House> houseMap = houseList.stream().collect(Collectors.toMap(House::getOwnerid, o -> o));
        System.out.println(houseMap);
        /**
         * {
         * 1=House{id=1, ownerid=1, housename='aa', address='北京海淀'},
         * 2=House{id=2, ownerid=2, housename='bb', address='湖北武汉'},
         * 3=House{id=3, ownerid=3, housename='cc', address='浙江杭州'}
         * }
         */

        //此处的效果同houseMap
        Map<Integer, House> houseMap1 = houseList.stream().collect(Collectors.toMap(House::getOwnerid, Function.identity()));
        System.out.println(houseMap1);
        /**
         * {1=House{id=1, ownerid=1, housename='aa', address='北京海淀'},
         * 2=House{id=2, ownerid=2, housename='bb', address='湖北武汉'},
         * 3=House{id=3, ownerid=3, housename='cc', address='浙江杭州'}}
         */


        ArrayList<House> houseList2 = new ArrayList<>();
        houseList2.add(new House(1, 1, "aa", "北京海淀1"));
        houseList2.add(new House(2, 2, "bb", "湖北武汉2"));
        houseList2.add(new House(3, 3, "cc", "浙江杭州3"));
        houseList2.add(new House(4, 3, "dd", "浙江杭州4"));

        try {
            // 当key 出现重复
            Map<Integer, String> collect2 = houseList2.stream().collect(Collectors.toMap(House::getOwnerid, House::getHousename));
            System.out.println("collect2: " + collect2);    // 报错 无法输出
        } catch (Exception e) {
            System.out.println("Ownerid重复 " + e.getMessage());  // Ownerid重复 Duplicate key cc
        }


        Map<Integer, String> collect3 = houseList2.stream().collect(Collectors.toMap(House::getOwnerid, House::getHousename, (v1, v2) -> v2));
        System.out.println("collect3: " + collect3);    // collect3: {1=aa, 2=bb, 3=dd}
        Map<Integer, String> collect4 = houseList2.stream().collect(Collectors.toMap(House::getOwnerid, House::getHousename, (v1, v2) -> v1));
        System.out.println("collect4: " + collect4);    // collect4: {1=aa, 2=bb, 3=cc}

        Map<Integer, House> collect6 = houseList2.stream().collect(Collectors.toMap(House::getOwnerid, Function.identity(), (v1, v2) -> v1));
        System.out.println("collect6: " + collect6);    // collect6: {1=House(id=1, ownerid=1, housename=aa, address=北京海淀), 2=House(id=2, ownerid=2, housename=bb, address=湖北武汉), 3=House(id=3, ownerid=3, housename=cc, address=浙江杭州)}

        Map<Integer, String> collect5 = houseList2.stream().collect(Collectors.toMap(House::getOwnerid, House::getHousename, (v1, v2) -> v1 + v2));
        System.out.println("collect5: " + collect5);    // collect5: {1=aa, 2=bb, 3=ccdd}

        // 根据字段去重
        List<House> filter1 = houseList2.stream().filter(distinctByKey(h -> h.getOwnerid())).collect(Collectors.toList());
        System.out.println("filter1: " + filter1);  // filter1: [House(id=1, ownerid=1, housename=aa, address=北京海淀1), House(id=2, ownerid=2, housename=bb, address=湖北武汉2), House(id=4, ownerid=3, housename=dd, address=浙江杭州4)]

    }

    private static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
        Map<Object, Boolean> map = new ConcurrentHashMap<>();
        return t -> map.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
    }

    @Test
    public void lsitToString() {
        // 字符串 转 List
        List<String> list = Arrays.asList("One", "Two", "Three", "Four", "Five", "Six");
        System.out.println("list = " + list);
    }

    @Test
    public void joining() {
        // 字符串 转 List
        List<String> list = Arrays.asList("One", "Two", "Three", "Four", "Five", "Six");
        System.out.println("list = " + list);

        // List 按规则分割
        String str1 = String.join("_", list);
        System.out.println("List 按规则分割:\t" + str1);  // List 按规则分割:	One_Two_Three_Four_Five_Six

        // List 按规则分割
        String str2 = String.join(",", list);
        System.out.println("List 按规则分割:\t" + str2);  // List 按规则分割:	One,Two,Three,Four,Five,Six

        // List 按规则分割
        String str3 = String.join(", ", list);
        System.out.println("List 按规则分割:\t" + str3);  // List 按规则分割:	One, Two, Three, Four, Five, Six


        List<Person> personList = new ArrayList<>();
        personList.add(new Person("张三", "男", 27));
        personList.add(new Person("李四", "男", 14));
        personList.add(new Person("王五", "女", 17));
        personList.add(new Person("赵六", "女", 34));
        personList.add(new Person("赵六", "女", 34));

        //joining: 拼接
        System.out.println("//joining: 拼接");
        String join = personList.stream().map(x -> x.getName()).collect(Collectors.joining());
        System.out.println(join);   // 张三李四王五赵六赵六

        String join1 = personList.stream().map(x -> x.getName()).collect(Collectors.joining("-"));
        System.out.println(join1);  // 张三李四王五赵六赵六

        String join2 = personList.stream().map(x -> x.getName()).collect(Collectors.joining("-", "前缀", "后缀"));
        System.out.println(join2);  // 前缀张三-李四-王五-赵六-赵六后缀
    }

    @Test
    public void lsitToMap() {
        List<Person> personList = new ArrayList<>();
        personList.add(new Person("张三", "男", 27));
        personList.add(new Person("李四", "男", 14));
        personList.add(new Person("王五", "女", 17));
        personList.add(new Person("赵六", "女", 34));
        personList.add(new Person("赵六", "女", 34));

        // 过滤年龄大于18岁的
        Map<Boolean, List<Person>> personsByAge = personList.stream().collect(Collectors.partitioningBy(p -> p.getAge() > 18));
        System.out.println(JSON.toJSONString(personsByAge));
        /*
        {
            "false":[
                {
                    "age":14,
                    "gender":"男",
                    "name":"李四",
                    "uuid":"4ab035c1"
                },
                {
                    "age":17,
                    "gender":"女",
                    "name":"王五",
                    "uuid":"d9bc5e18"
                }
            ],
            "true":[
                {
                    "age":27,
                    "gender":"男",
                    "name":"张三",
                    "uuid":"7928ea48"
                },
                {
                    "age":34,
                    "gender":"女",
                    "name":"赵六",
                    "uuid":"dc71c87b"
                },
                {
                    "age":34,
                    "gender":"女",
                    "name":"赵六",
                    "uuid":"3e143936"
                }
            ]
        }
        */

    }
}
